/**  
 * @author renbangjie renbangjie@126.com  
 * @date 2014-11-25 下午5:56:34
 * @version V1.0  
 * <b>Copyright (c)</b> 2014医信金融信息服务（上海）有限公司-版权所有<br/>
 */
package com.yjd.comm.util;

import java.io.IOException;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger;
import org.springframework.core.task.TaskExecutor;

import com.yjd.comm.sms.service.IMarketSmsService;
import com.yjd.comm.system.model.SysParamModel;
import com.yjd.comm.system.util.SysParamUtil;
import com.yjd.comm.vo.Constant.SysParamKeyEnum;

import cn.entinfo.WebServiceSoapProxy;

/**
 * 沃动科技短信发送相关方法
 * 
 * @author renbangjie renbangjie@126.com
 * @date 2014-11-25 下午5:56:34
 */
public class MessageSender implements Serializable{

	/**
	* @Fields serialVersionUID : TODO
	*/
	private static final long serialVersionUID = 1L;

	private static final Logger logger = Logger.getLogger(MessageSender.class);
	
	//签名
	private String signature = "【医界贷】";
	
	private TaskExecutor taskExecutor;
	
	@Resource
	private IMarketSmsService marketSmsService;

	/**
	 * 序列号
	 */
	private String sn = "SDK-MON-010-00032";

	/**
	 * 密码
	 */
	private String password = "386241";

	/**
	 * 加密后的密码
	 */
	private String pwd;

	/**
	 * 地址
	 */
	private String serviceURL = "http://sdk.entinfo.cn:8061/webservice.asmx";

	/**
	 * 备用地址
	 */
	private String serviceURL_backup = "http://sdk2.entinfo.cn:8061/webservice.asmx";

	/**
	 * 默认使用地址
	 */
	private String serviceURL_default = "http://sdk.entinfo.cn:8061/webservice.asmx";

	/**
	 * 尝试连接次数限制
	 */
	private int maxCount = 3;

	/**
	 * 分批处理的数量
	 */
	private int batchCount = 4;
	
	
	/**
	 * 批量发送短信
	 * 
	 * @param mobiles
	 *            手机号集合
	 * @param content
	 *            短信内容
	 * @param stime
	 *            发送时间,为空立即发送 yyyy-MM-dd hh:mm:ss
	 * @return String
	 * @throws RemoteException
	 */
	public boolean send(List<String> mobiles, String title, String content,
			String stime) throws RemoteException {
		if (mobiles == null || mobiles.isEmpty()) {
			return false;
		}

		int size = mobiles.size();
		if (size > batchCount) {
			threadPoolSend(mobiles, title, content, stime);
			logger.info("----------------大批量短信已交由线程池发送-----------------");
		} else {
			return this.send(listToString(mobiles), title, content, stime,
					MessageType.normal);
		}
		return true;
	}
	
	/**
	 * 线程池批量发送
	* @param mobiles
	* @param title
	* @param content
	* @param time
	 */
	private void threadPoolSend(List<String> mobiles, String title, String content, String time){
		
		int size = mobiles.size(), end = batchCount;
		// 计算分批发送次数
		int temp = (size % batchCount) == 0 ? (size / batchCount)
				: (size / batchCount) + 1;
		logger.info("开始发送:一共" +size+ "条,每次发送" +end+ "条,共发送" + temp+ "次");
		// 每次发送的集合
		List<String> sub = new ArrayList<String>();

		for (int i = 0; i < temp; i++) {
			if (mobiles.size() <= batchCount) {
				end = mobiles.size();
			}
			sub = mobiles.subList(0, end);
			taskExecutor.execute(new Send(listToString(sub), title, content, time));
			mobiles.removeAll(sub); // 删除已发送的手机号
		}
	}
	
	

	/**
	 * 发送短信的第三方接口
	 * 
	 * @param mobile
	 * @param content
	 * @param stime
	 * @param type
	 * @return boolean
	 * @throws RemoteException
	 */
	public boolean send(String mobile, String title, String content,
			String stime, MessageType type) {
		try {
			boolean bool = false;
			WebServiceSoapProxy proxy = getServiceSoapProxy();
			// 普通短信
			if (type.getCode() == MessageType.normal.getCode()) {
				bool = proxy.mdsmssend(sn, pwd, mobile, content + signature, null,
						stime, null, "15") != null;
			} else if (type.getCode() == MessageType.custom.getCode()) { // 个性化短信
				bool = proxy.mdgxsend(stime, stime, mobile, content, null,
						stime, null, "15") != null;
			}
			return bool;
		} catch (RemoteException e) {
			logger.info("发送短信异常,异常原因是:" + e.getMessage());
			return false;
		}
	}

	/**
	 * 发送大批量短信的子线程
	 * @author renbangjie renbangjie@126.com
	 * @date 2014-12-1 下午1:12:48
	 */
	class Send extends Thread {

		private String mobiles;

		private String content;

		private String time;

		private String title;

		public Send(String mobiles, String title, String content,
				String time) {
			this.mobiles = mobiles;
			this.content = content;
			this.time = time;
			this.title = title;
		}

		@Override
		public void run() {
			send(mobiles, title, content, time, MessageType.normal);
		}

	}

	public WebServiceSoapProxy getServiceSoapProxy() {
		return new WebServiceSoapProxy(serviceURL_default);
	}

	/**
	 * 初始化参数
	 * @throws Exception 
	 */
	public void init() throws Exception {
		SysParamModel param = SysParamUtil.getSysParamModel(SysParamKeyEnum.MARKET_SIGNATURE);
		signature = param.getParam_value();
		
		pwd = DigestUtils.md5Hex(sn + password).toUpperCase();
		// 检测主地址是否通畅
		new AddressThread().start();
	}

	public static void main(String[] args) throws Exception {
		new MessageSender().init();
	}

	/**
	 * 主备地址切换线程
	 * 
	 * @author renbangjie renbangjie@126.com
	 * @date 2014-11-28 上午11:21:28
	 */
	class AddressThread extends Thread {
		private int count = 0;
		private HttpURLConnection httpconn;
		private int responseCode = HttpURLConnection.HTTP_OK;

		/**
		 * 尝试链接
		 * 
		 * @param url
		 * @throws IOException
		 *             , SocketException
		 */
		public void connect(String url) throws IOException {
			// 检测主地址是否可用
			httpconn = (HttpURLConnection) (new URL(serviceURL)
					.openConnection());
			httpconn.setConnectTimeout(10000);
			httpconn.connect();
			if (httpconn.getResponseCode() != responseCode) {
				serviceURL_default = serviceURL_backup;
				logger.info("短信通道" + serviceURL + "异常,切换到备用地址"
						+ serviceURL_default + ",http状态码:"
						+ httpconn.getResponseCode() + "异常信息:"
						+ httpconn.getResponseMessage());
				this.sleepThread(1000 * 20);
				return;
			}

		}

		@Override
		public void run() {
			try {
				while (true) {
					// 检测主地址是否可用
					this.connect(serviceURL);
					// 默认地址设为主地址
					serviceURL_default = serviceURL;
					count = 0;
					this.sleepThread(1000 * 50);
				}
			} catch (IOException e) {
				count++;
				if (count > maxCount) {
					logger.info("第" + count + "次连接沃动科技短信接口主地址失败,切换到备用地址");
					// 切换到备用地址
					serviceURL_default = serviceURL_backup;
					count = 0;
					this.sleepThread(1000 * 20);
				}
				logger.info("第" + count + "次连接沃动科技短信接口主地址失败." + e.getMessage());
				this.sleepThread(1000 * 10);
			}

		}

		/**
		 * 线程休眠
		 * 
		 * @param times
		 *            休眠时间
		 */
		private void sleepThread(int times) {
			try {
				Thread.sleep(times);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * list转换为String并去重复
	 * 
	 * @param list
	 * @return String
	 */
	public String listToString(List<String> list) {
		Set<String> sub = new HashSet<String>();
		for (String temp : list) {
			sub.add(temp);
		}
		return sub.toString().replaceAll("\\[|\\]", "");
	}

	/**
	 * 短信类型
	 * 
	 * @author renbangjie renbangjie@126.com
	 * @date 2014-12-1 下午1:52:01
	 */
	enum MessageType {

		normal(0, "普通短信"), custom(1, "个性短信");

		private int code;
		private String label;

		private MessageType(int code, String label) {
			this.code = code;
			this.label = label;
		}

		public int getCode() {
			return code;
		}

		public void setCode(int code) {
			this.code = code;
		}

		public String getLabel() {
			return label;
		}

		public void setLabel(String label) {
			this.label = label;
		}
	}

	public void setSn(String sn) {
		this.sn = sn;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setServiceURL(String serviceURL) {
		this.serviceURL = serviceURL;
	}

	public void setServiceURL_backup(String serviceURL_backup) {
		this.serviceURL_backup = serviceURL_backup;
	}

	public void setServiceURL_default(String serviceURL_default) {
		this.serviceURL_default = serviceURL_default;
	}

	public void setMaxCount(int maxCount) {
		this.maxCount = maxCount;
	}

	public void setBatchCount(int batchCount) {
		this.batchCount = batchCount;
	}

	public void setTaskExecutor(TaskExecutor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}
}
